package com.my.demo.demo2.util;

import com.my.demo.demo2.annotation.IgnoreSign;
import org.apache.tomcat.util.security.MD5Encoder;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shanchong
 * @date 2019-07-12
 **/
public class SignUtil {

    public static String doSign(String params,String privateKey){
        // 解密由base64编码的私钥
        byte[] bytesKey = new byte[0];
        try {
            bytesKey = (new BASE64Decoder()).decodeBuffer(privateKey);
            // 构造PKCS8EncodedKeySpec对象
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(bytesKey);
            // KEY_ALGORITHM 指定的加密算法
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            // 取私钥匙对象
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
            // 用私钥对信息生成数字签名
            Signature signature = Signature.getInstance("MD5WithRSA");
            signature.initSign(priKey);
            signature.update(params.getBytes("GBK"));
            String sign = (new BASE64Encoder()).encodeBuffer(signature.sign());
            return sign;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String sortParam(Object object){
        final Map<String, Object> map = object2Map(object);
        return map.entrySet().stream()
                .sorted(Comparator.comparing(Map.Entry::getKey))
                .map(e-> e.getKey()+"="+e.getValue())
                .collect(Collectors.joining("&"));
    }

    public static Map<String,Object> object2Map(Object object) {
        final HashMap<String, Object> map = new HashMap<>();
        final Method[] methods = object.getClass().getMethods();
        for (int i = 0; i < methods.length; i++) {
            final Method method = methods[i];
            final String methodName = method.getName();
            final IgnoreSign ignoreSign = method.getAnnotation(IgnoreSign.class);
            if (methodName.startsWith("get")
                    &&!methodName.equals("getClass")&&ignoreSign==null){
                Object o = null;
                try {
                    o = method.invoke(object);
                    if (o==null){
                        continue;
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
                final String getMethodName = methodName.replace("get", "");
                map.put(getMethodName.substring(0,1).toLowerCase()+getMethodName.substring(1),o);
            }
        }
        return map;
    }

}
